///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _CTEXTRUN_H_
#define _CTEXTRUN_H_

#include <buola/buola.h>
#include <buola/algorithm/hash.h>

namespace buola { namespace img {

///\addtogroup utility
///@{

////////////////////////////////////////////////////////////////////////////

/// text run container

/// This template represents a division of a string into different runs,
/// and associates a value of a certain type to each of the runs
///
////////////////////////////////////////////////////////////////////////////

template<typename tType>
class CTextRun : public UUncopiable
{
public:
    explicit CTextRun(int pCapacity=0)
        :	mLimits(pCapacity),
            mValues(pCapacity)
    {
    }

    int count() const			{	return mLimits.size();	}

    void clear()
    {
        mLimits.clear();
        mValues.clear();
    }
    
    int GetIndex(int pLimit)
    {
        int i=0;
        
        while(i<mLimits.size()&&mLimits[i]<=pLimit) i++;
        
        return i;
    }

    int GetLimit() const
    {
        if(mLimits.empty())
            return 0;
        return mLimits.back();
    }
    
    int GetLimit(int pRun) const
    {
        return mLimits[pRun];
    }
    
    const tType &GetValue(int pRun) const
    {
        return mValues[pRun];
    }

    tType &GetValue(int pRun)
    {
        return mValues[pRun];
    }

    void SetLimit(int pRun,int pLimit)
    {
        mLimits[pRun]=pLimit;
    }

    void SetValue(int pRun,const tType &pValue)
    {
        mValues[pRun]=pValue;
    }

    const std::vector<int> &Limits() const		{	return mLimits;	}
    const std::vector<tType> &Values() const	{	return mValues;	}

    void Add(int pLimit,const tType &pValue)
    {
        mLimits.push_back(pLimit);
        mValues.push_back(pValue);
    }

    void AddBreak(int pLimit)
    {
        int i=0;
        while(mLimits[i]<pLimit) continue;
        
        if(mLimits[i]!=pLimit)
        {
            mLimits.insert(mLimits.begin()+i,pLimit);
            mValues.insert(mValues.begin()+i,mValues[i]);
        }
    }

private:
    std::vector<int> mLimits;
    std::vector<tType> mValues;
};

//! combines two text run containers into one using a custom combination 
//! function

template<typename tDest,typename tType1,typename tType2,typename tFunc>
inline void combine_runs(CTextRun<tDest> &pDst,const CTextRun<tType1> &pR1,
      const CTextRun<tType2> &pR2,const tFunc &pFunc)
{
    pDst.clear();
    
    int i1=0,i2=0;
    
    while(i1<pR1.count()&&i2<pR2.count())
    {
        int l1=pR1.GetLimit(i1);
        int l2=pR2.GetLimit(i2);
        
        if(l1<l2)
        {
            pDst.Add(l1,pFunc(pR1.GetValue(i1),pR2.GetValue(i2)));
            i1++;
        }
        else
        {
            pDst.Add(l2,pFunc(pR1.GetValue(i1),pR2.GetValue(i2)));
            i2++;
            if(l1==l2)
                i1++;
        }
    }
}

//! combines three text run containers into one using a custom combination 
//! function

template<typename tDest,typename tType1,typename tType2,typename tType3,typename tFunc>
inline void combine_runs(CTextRun<tDest> &pDst,const CTextRun<tType1> &pR1,
      const CTextRun<tType2> &pR2,const CTextRun<tType3> &pR3,const tFunc &pFunc)
{
    pDst.clear();
    
    int i1=0,i2=0,i3=0;
    
    while(i1<pR1.count()&&i2<pR2.count()&&i3<pR3.count())
    {
        int l1=pR1.GetLimit(i1);
        int l2=pR2.GetLimit(i2);
        int l3=pR3.GetLimit(i3);
        
        if(l1<l2)
        {
            if(l1<l3)
            {
                pDst.Add(l1,pFunc(pR1.GetValue(i1),pR2.GetValue(i2),pR3.GetValue(i3)));
                i1++;
            }
            else
            {
                pDst.Add(l3,pFunc(pR1.GetValue(i1),pR2.GetValue(i2),pR3.GetValue(i3)));
                i3++;
                if(l1==l3)
                    i1++;
            }
        }
        else
        {
            if(l2<l3)
            {
                pDst.Add(l2,pFunc(pR1.GetValue(i1),pR2.GetValue(i2),pR3.GetValue(i3)));
                i2++;
                if(l1==l2)
                    i1++;
            }
            else
            {
                pDst.Add(l3,pFunc(pR1.GetValue(i1),pR2.GetValue(i2),pR3.GetValue(i3)));
                i3++;
                if(l2==l3)
                    i2++;
                if(l1==l3)
                    i1++;
            }
        }
    }
}

//! combines two text run containers into one

template<typename tType1,typename tType2>
inline void combine_runs(CTextRun<std::pair<tType1,tType2>> &pDst,
        const CTextRun<tType1> &pR1,const CTextRun<tType2> &pR2)
{
    combine_runs(pDst,pR1,pR2,std::make_pair<tType1,tType2>);
}

///@}

/*namespace img*/ } /*namespace buola*/ }

#endif
